﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Text.RegularExpressions;
using System.Windows.Forms;
using HDQApp.Common;
using HWND = System.IntPtr;

namespace HDQApp
{
    /// <summary>
    /// SyntaxEditor 的摘要说明。
    /// </summary>
    public class SyntaxEditor : System.Windows.Forms.RichTextBox
    {
        /// <summary> 
        /// 必需的设计器变量。

        /// </summary>
        private System.ComponentModel.Container components = null;
        int line;               //============ 这个变量没有使用 ===========


        //使用win32api：SendMessage来防止控件着色时的闪烁现象
        [DllImport("user32")]
        private static extern int SendMessage(HWND hwnd, int wMsg, int wParam, IntPtr lParam);
        private const int WM_SETREDRAW = 0xB;


        public SyntaxEditor()
        {
            // 该调用是 Windows.Forms 窗体设计器所必需的。
            InitializeComponent();

            base.Font = new Font("Lucida Console", 9, FontStyle.Regular);       //指定了字体类型=字库
        }

        /// <summary>
        /// 设计器支持所需的方法 - 不要使用代码编辑器 
        /// 修改此方法的内容。
        /// </summary>
        private void InitializeComponent()
        {
            this.SuspendLayout();       //临时挂起控件的布局逻辑。

            this.ResumeLayout(false);   //恢复正常的布局逻辑，可以选择强制对挂起的布局请求立即进行布局。若要执行挂起的布局请求，则为 true；否则为 false。

        }

        /// <summary>
        /// 清理所有正在使用的资源。
        /// </summary>
        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                if (components != null)
                    components.Dispose();       //释放内存
            }
            base.Dispose(disposing);
        }




        /// <summary>
        /// 蓝色(#0000FF)
        /// </summary>
        HashSet<string> lstKWordByBlue = SQLHandler.GetKeyWordsByBlue();
        /// <summary>
        /// 牡丹红(#FF00FF)
        /// </summary>
        HashSet<string> lstKWordByPeony = SQLHandler.GetKeyWordsByPeony();
        /// <summary>
        /// 灰色(#C0C0C0)
        /// </summary>
        HashSet<string> lstKWordByGray = SQLHandler.GetKeyWordsByGray();

        /// <summary>
        /// (绿色)#F9F900
        /// </summary>
        HashSet<string> lstDeclareByGreen = new HashSet<string>();

        /// <summary>
        /// 是否粘贴
        /// </summary>
        bool isPaste = false;
        protected override void OnKeyDown(System.Windows.Forms.KeyEventArgs e)
        {
            //监视 是否按下 空格键 来处理单行文本内容
            if (e.KeyCode == System.Windows.Forms.Keys.Space)
            {
                isSpace = true;
            }
            else
            {
                isSpace = false;
            }

            if (e.Control && e.KeyCode == Keys.V)
            {
                isPaste = true;
            }
            //此处 处理调用自动完成事件,不可删除！！！
            base.OnKeyDown(e);

        }

        protected override void OnKeyPress(KeyPressEventArgs e)
        {
            if (isPaste)
            {
                DoHanle(0, this.Text);
                isPaste = false;
            }
        }

        protected override void OnKeyUp(System.Windows.Forms.KeyEventArgs e)
        {
            if (isPaste)
            {
                DoHanle(0, this.Text);
                isPaste = false;
            }
        }

        /// <summary>
        /// 是否空格（着色单行使用）
        /// </summary>
        bool isSpace = false;
        protected override void OnTextChanged(EventArgs e)
        {
            if (isSpace)//如果输入了空格时执行
            {
                //当前光标位置
                int selectStart = this.SelectionStart;
                //当前光标所在行
                int Intline = this.GetLineFromCharIndex(selectStart);
                //当前行光标所在行第一个字符的索引
                int currFirstCharIndex = this.GetFirstCharIndexFromLine(Intline);
                //当前行内容
                string content = this.Lines[Intline];

                DoHanle(currFirstCharIndex, content);
            }
            else if (!isPaste && !string.IsNullOrWhiteSpace(this.Text))//非输入空格并且非粘贴，但有文本内容
            {
                DoHanle(0, this.Text);
            }

        }
        void DoHanle(int selectStart, string text)
        {
            if (!string.IsNullOrWhiteSpace(this.Text))      //指示指定的字符串是 null、空还是仅由空白字符组成。
            {
                //重新查询可用 特性名称
                lstDeclareByGreen = SQLHandler.GetCustomeAttr();            //获得特性名称列表

                SendMessage(base.Handle, WM_SETREDRAW, 0, IntPtr.Zero);     //关闭控件重构功能

                Polish(selectStart, text);

                //重新定义光标位置
                if (isPaste)
                {
                    //粘贴则在当前文本尾部
                    selectStart = text.Length;
                }
                else
                {
                    //行内，则原有行第一个字符位置+当前行字符长度
                    selectStart = selectStart + text.Length;
                }

                this.Select(selectStart, 0);        //光标设置到原来位置   
                this.Focus();                       //获得焦点

                SendMessage(base.Handle, WM_SETREDRAW, 1, IntPtr.Zero);     //颜色设置结束后，打开重构控件功能
                this.Refresh();                                             //强制重构控件
            }
        }

        /// <summary>
        /// 文本着色
        /// </summary>
        /// <param name="beforeIndex">当前content外，应该累加的索引</param>
        /// <param name="content">文本内容</param>
        public void Polish(int beforeIndex, string content)
        {
            //查询解析 当前内容内所有的word，并获取其 在content中的索引位置
            Dictionary<string, List<int>> dictAllIndex = GetAllIndex(content, SplitChars);      //获取所有单词及对应索引
            foreach (var entity in dictAllIndex)        //遍历所有单词
            {
                string word = entity.Key;               //获取KEY值=单词
                int length = word.Length;               //获取单词的长度
                //所有该word的索引位置
                List<int> lstIndex = entity.Value;      //获取单词的位置索引,可能不止一个。

                //SQL关键字
                if (lstKWordByBlue.Contains<string>(word, StringComparer.OrdinalIgnoreCase))        //判断word包含在lstKWordByBlue中, OrdinalIgnoreCase: 不区分大小写的序号字符串比较。
                {
                    foreach (int currLineIndex in lstIndex)          //对多个索引遍历处理
                    {
                        int currentIndex = beforeIndex + currLineIndex;
                        this.Select(currentIndex, length);          //选择文本框中的文本范围
                        this.SelectedText = word.ToUpper();         //选取范围内的单词全部高写成大写
                        //重新设置SelectedText后，需要再次选择
                        this.Select(currentIndex, length);
                        //设置颜色及字体
                        this.SelectionColor = System.Drawing.ColorTranslator.FromHtml("#0000FF");
                        this.SelectionFont = new Font("Lucida Console", 9, FontStyle.Bold);
                    }
                }
                //SQL函数
                else if (lstKWordByPeony.Contains<string>(word, StringComparer.OrdinalIgnoreCase))
                {
                    foreach (int currLineIndex in lstIndex)
                    {
                        int currentIndex = beforeIndex + currLineIndex;
                        this.Select(currentIndex, length);
                        this.SelectedText = word.ToUpper();
                        //重新设置SelectedText后，需要再次选择
                        this.Select(currentIndex, length);
                        //设置颜色及字体
                        this.SelectionFont = new Font("Lucida Console", 9, FontStyle.Bold);
                        this.SelectionColor = System.Drawing.ColorTranslator.FromHtml("#FF00FF");
                    }
                }
                //逻辑运算符
                else if (lstKWordByGray.Contains<string>(word, StringComparer.OrdinalIgnoreCase))
                {
                    foreach (int currLineIndex in lstIndex)
                    {
                        int currentIndex = beforeIndex + currLineIndex;
                        this.Select(currentIndex, length);
                        this.SelectedText = word.ToUpper();
                        //重新设置SelectedText后，需要再次选择
                        this.Select(currentIndex, length);
                        //设置颜色及字体
                        this.SelectionFont = new Font("Lucida Console", 9, FontStyle.Bold);
                        this.SelectionColor = System.Drawing.ColorTranslator.FromHtml("#C0C0C0");
                    }
                }
                //自定义特性名称
                else if (lstDeclareByGreen.Contains<string>(word, StringComparer.OrdinalIgnoreCase))
                {
                    foreach (int currLineIndex in lstIndex)
                    {
                        int currentIndex = beforeIndex + currLineIndex;
                        this.Select(currentIndex, length);
                        this.SelectedText = word;
                        //重新设置SelectedText后，需要再次选择
                        this.Select(currentIndex, length);
                        //设置颜色及字体
                        this.SelectionFont = new Font("Lucida Console", 9, FontStyle.Bold);
                        this.SelectionColor = Color.Green;
                    }
                }
                //其他任何字符
                else
                {
                    foreach (int currLineIndex in lstIndex)
                    {
                        int currentIndex = beforeIndex + currLineIndex;
                        this.Select(currentIndex, length);
                        this.SelectionColor = Color.Black;
                        this.SelectionFont = new Font("Lucida Console", 9, FontStyle.Regular);
                    }
                }
            }
        }

        /// <summary>
        /// 定义分割字符
        /// </summary>
        static string[] SplitChars = new string[] { " ", ";", ".", "\n", "(", ")", "}", "{", "\"", "[", "]" };    //区分单词的分隔符


        //static string[] SplitChars = new string[] //区分单词的分隔符
        //{ 
        //    //一些正则字符
        //    "a-z","\\b","\\B","\\cx","\\d",
        //    "\\D","\\f","\\n","\\r","\\s","\\S","\\t","\\v","\\w","\\W",
        //    //键盘上所有字符
        //    "~","!","#","$","%","^","&","*","(",")","+","-","=","|","\\","[","]",";",":","<",">","《","》","?",",","'","\"",".","/","{","}","【","】","；‘","，","。","、","·",                
        //    //空白字符
        //    "　"," "
        //    //"@","_",
        //};

        /// <summary>
        /// 查询字符串中 所有单词的起始位置
        /// </summary>
        /// <param name="content">被查询字符</param>
        /// <param name="splitChars">分割char数组</param>
        /// <returns></returns>
        static Dictionary<string, List<int>> GetAllIndex(string content, string[] splitChars)
        {
            //content = content.ToLower();
            string[] words = content.Split(splitChars, StringSplitOptions.RemoveEmptyEntries);
            HashSet<string> lstWord = new HashSet<string>(words);
            Dictionary<string, List<int>> dictIndex = new Dictionary<string, List<int>>();
            int startIndex = 0;
            foreach (string wd in lstWord)
            {
                //string word = wd.ToLower();
                string word = wd;
                while (startIndex < content.Length) //如果当前查找的索引位置小于 内容长度，则该字符就可能存在，那么久继续查找
                {
                    int findIndex = content.IndexOf(word, startIndex);
                    if (findIndex > -1 && !string.IsNullOrEmpty(word))
                    {
                        List<int> lstIndex = null;
                        if (dictIndex.TryGetValue(word, out lstIndex))
                        {
                            lstIndex.Add(findIndex);
                            dictIndex.Remove(word);
                            dictIndex.Add(word, lstIndex);
                        }
                        else
                        {
                            lstIndex = new List<int>();
                            lstIndex.Add(findIndex);
                            dictIndex.Add(word, lstIndex);
                        }
                        startIndex = findIndex + word.Length;
                    }
                    else//当找不到之后，则跳出对于当前字符的查找，继续下一个字符的查找
                    {
                        startIndex = 0;
                        break;
                    }
                }
            }
            return dictIndex;
        }



        static Dictionary<string, List<int>> GetAllIndex2(string content, string[] splitChars)
        {
            content = content.ToLower();
            string[] words = content.Split(splitChars, StringSplitOptions.RemoveEmptyEntries);
            List<string> lstWord = new List<string>(words.Distinct());
            Dictionary<string, List<int>> dictIndex = new Dictionary<string, List<int>>();

            foreach (string wd in lstWord)
            {
                MatchCollection mats = Regex.Matches(content, @"([\s\(]?)(" + wd + @")([\s\(])", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.Multiline);

                if (mats.Count > 0)
                {
                    List<int> lstIndex = new List<int>();
                    foreach (Match mat in mats)
                    {
                        if (mat.Success)
                        {
                            string gpVal = mat.Groups[1].Value;
                            int index = mat.Index;
                            if (gpVal.Length > 0)
                            {
                                index += 1;
                            }
                            lstIndex.Add(index);
                        }
                    }
                    dictIndex.Add(wd.ToLower(), lstIndex);
                }
                else
                {
                    mats = Regex.Matches(content, @"(.)(" + wd + @")(.)", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.Multiline);
                    if (mats.Count > 0)
                    {
                        List<int> lstIndex = new List<int>();
                        foreach (Match mat in mats)
                        {
                            if (mat.Success)
                            {
                                string gpVal = mat.Groups[1].Value;
                                int index = mat.Index;
                                if (gpVal.Length > 0)
                                {
                                    index += 1;
                                }
                                lstIndex.Add(index);
                            }
                        }
                        dictIndex.Add(wd.ToLower(), lstIndex);
                    }
                }
            }
            return dictIndex;
        }
    }

}
